package cn.xo68.boot.auth.server.web.token;

import cn.xo68.boot.auth.server.domain.OauthRefreshToken;
import cn.xo68.boot.auth.server.domain.OauthToken;
import cn.xo68.boot.auth.server.properties.AuthServerProperties;
import cn.xo68.boot.auth.server.service.OauthRefreshTokenService;
import cn.xo68.boot.auth.server.service.OauthTokenService;
import cn.xo68.boot.auth.server.token.OAuthTokenRequestExt;
import cn.xo68.boot.auth.server.token.TokenRequestCheckedResult;
import cn.xo68.boot.auth.server.token.impl.TokenRequestCheckOnAuthorizationCode;
import cn.xo68.boot.auth.server.token.impl.TokenRequestCheckOnPassword;
import cn.xo68.boot.auth.server.token.impl.TokenRequestCheckOnRefresToken;
import cn.xo68.boot.auth.server.util.AuthServerUtils;
import cn.xo68.core.date.DateTime;
import cn.xo68.core.util.StringTools;
import org.apache.oltu.oauth2.as.issuer.MD5Generator;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *  令牌申请控制器
 * @author admin
 * @date 2018/7/31 22:40
 *
 */
@RestController
public class OAuthTokenController {

    private static  final Logger logger= LoggerFactory.getLogger(OAuthTokenController.class);

    @Autowired
    private AuthServerUtils authServerUtils;

    @Autowired
    private TokenRequestCheckOnPassword tokenRequestCheckOnPassword;
    @Autowired
    private TokenRequestCheckOnAuthorizationCode tokenRequestCheckOnAuthorizationCode;
    @Autowired
    private TokenRequestCheckOnRefresToken tokenRequestCheckOnRefresToken;

    @Autowired
    private AuthServerProperties authServerProperties;

    @Autowired
    private OauthRefreshTokenService oauthRefreshTokenService;


    @Autowired
    private OauthTokenService oauthTokenService;

    @RequestMapping(value = "/oauth/token",method = RequestMethod.POST)
    public HttpEntity token(HttpServletRequest request, HttpServletResponse response)  throws OAuthSystemException{
        OAuthResponse oAuthResponse=null;

        OAuthIssuer oAuthIssuer=new OAuthIssuerImpl(new MD5Generator());
        try {
            OAuthTokenRequestExt tokenRequest = new OAuthTokenRequestExt(request);

            tokenRequest.addTokenRequestCheck(GrantType.PASSWORD, tokenRequestCheckOnPassword);
            tokenRequest.addTokenRequestCheck(GrantType.AUTHORIZATION_CODE, tokenRequestCheckOnAuthorizationCode);
            tokenRequest.addTokenRequestCheck(GrantType.REFRESH_TOKEN, tokenRequestCheckOnRefresToken);

            TokenRequestCheckedResult tokenRequestCheckedResult=tokenRequest.check();

            logger.debug("tokenRequestCheckedResult:{}", tokenRequestCheckedResult);

            String accessToken=oAuthIssuer.accessToken();
            String refreshToken=oAuthIssuer.refreshToken();

            //持久化令牌信息及相关信息
            OauthToken oauthToken=new OauthToken();
            oauthToken.setToken(accessToken);
            oauthToken.setUserId(tokenRequestCheckedResult.getOauthUser().getUserId());
            oauthToken.setAccount(tokenRequestCheckedResult.getOauthUser().getAccount());
            oauthToken.setUserName(tokenRequestCheckedResult.getOauthUser().getUserName());
            oauthToken.setClientId(tokenRequestCheckedResult.getOauth2Client().getClientId());
            oauthToken.setClientName(tokenRequestCheckedResult.getOauth2Client().getClientName());
            oauthToken.setCreateTime(DateTime.Now().getDate());
            oauthToken.setExpireTime(DateTime.Now().addSecond(authServerProperties.getTokenExpireSeconds()).getDate());
            oauthToken.setRefreshToken(refreshToken);
            oauthTokenService.insert(oauthToken);

            String[] grantTypes=StringTools.tokenizeToStringArray(tokenRequestCheckedResult.getOauth2Client().getAuthorizedGrantTypes(),",");
            //if(grantTypes.)

            //持久化刷新令牌信息
            OauthRefreshToken oauthRefreshToken=new OauthRefreshToken();
            oauthRefreshToken.setToken(accessToken);
            oauthRefreshToken.setRefreshToken(refreshToken);
            oauthRefreshToken.setClientId(tokenRequestCheckedResult.getOauth2Client().getClientId());
            oauthRefreshToken.setUserId(tokenRequestCheckedResult.getOauthUser().getUserId());
            oauthRefreshToken.setCreateTime(DateTime.Now().getDate());
            oauthRefreshToken.setExpireTime(DateTime.Now().addSecond(authServerProperties.getRefreshTokenExpireSeconds()).getDate());
            oauthRefreshTokenService.insert(oauthRefreshToken);

            oAuthResponse=OAuthASResponse
                    .tokenResponse(HttpServletResponse.SC_OK)
                    .setAccessToken(accessToken)
                    .setRefreshToken(refreshToken)
                    .setTokenType("Bearer")
                    .setParam("uid",tokenRequestCheckedResult.getOauthUser().getUserId())
                    .setParam("uname",tokenRequestCheckedResult.getOauthUser().getUserName())
                    .location("")
                    .setExpiresIn(String.valueOf(authServerProperties.getTokenExpireSeconds()))
                    .buildJSONMessage();

        } catch (OAuthProblemException e) {
            //HttpServletResponse.SC_FOUND
            oAuthResponse = OAuthASResponse
                    .errorResponse(HttpServletResponse.SC_OK)
                    .location(e.getRedirectUri())
                    .error(e)
                    .buildJSONMessage();
        }
        MediaType mediaType=MediaType.APPLICATION_JSON_UTF8;
        HttpHeaders headers = authServerUtils.buildHeaders(oAuthResponse.getHeaders());

        return ResponseEntity
                .status(oAuthResponse.getResponseStatus())
                .headers(headers)
                .contentType(mediaType)
                .body(oAuthResponse.getBody());
    }
}
